#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fs.h>  
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/timer.h>
#include <linux/uaccess.h>
#include <linux/cdev.h> 
#include <linux/pwm.h>
#include <linux/delay.h>
#include <linux/miscdevice.h>
/**********************************************************************************
Copyright (C), by AppleCai
Project                      : Study Kernel
Description                  : BSP level for cdev
History                      :
CPU and Compiler             : AM335x,ARM-LINIX-GCC
GenDate                      : 2020-11-16
OwnerBy                      : Apple Cai
**********************************************************************************/
#include <linux/pwm.h>
#include <linux/delay.h>

struct pwm_device *pwm;
struct semaphore sem;

#define PMW_START   1
#define PMW_STOP    2
/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件，file结构体有个叫做private_data的成员变量
 * 					  一般在open的时候将private_data指向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int ApplePWM_open(struct inode *inode, struct file *filp)
{
	int ret = 0;
	if (!down_trylock(&sem)) //是否获得信号量,是 down_trylock(&lock)=0,否则非 0
	{
		pwm = pwm_request(0, "mypwmdev");
		if (NULL == pwm)
		{
			printk("no res\n");
			up(&sem); //释放信号量 lock
			return -ENODEV;
		}
		/*pwm_set_polarity(pwm, PWM_POLARITY_NORMAL);*/
		return ret;
	}
    else
    {
    	printk("busy\n");
        return -EBUSY; //返回错误信息:请求的资源不可用
    }

}

/*设备控制函数：*/ 
static long ApplePWM_ioctl(struct file *filp, unsigned int cmd,unsigned long arg)
{  
    switch (cmd) {
        case PMW_START: //if cmd=1 即进入 case PWM_IOCTL_SET_FREQ
            if (arg < 0) //如果设置的频率参数是 0
                return -EINVAL; //返回错误信息,表示向参数传递了无效的参数
            pwm_config(pwm, arg, 20000000);
			pwm_enable(pwm);
            break;
        case PMW_STOP: // if cmd=2 即进入 case PWM_IOCTL_STOP
            pwm_disable(pwm); //停止蜂鸣器
            break;
    }
    return 0; //成功返回 
}  

/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int ApplePWM_release(struct inode *inode, struct file *filp)
{
	pwm_disable(pwm);
    pwm_free(pwm);
	up(&sem); //释放信号量 lock
	return 0;
}

/* AppleEEP操作函数 */
static const struct file_operations ApplePWM_ops = {
	.owner = THIS_MODULE,
	.open = ApplePWM_open,
	.release = ApplePWM_release,
	.unlocked_ioctl = ApplePWM_ioctl,
};

static struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "ApplePWM",
    .fops = &ApplePWM_ops,
};
		   
static int __init ApplePWM_init(void)
{
    int ret=0;
    sema_init(&sem, 1);
    ret = misc_register(&misc); //注册一个 misc 设备
    printk ("ApplePWM initilize ok\n");
    return ret;
}

static void __exit ApplePWM_exit(void)
{
     misc_deregister(&misc); //注销设备
}


module_init(ApplePWM_init);
module_exit(ApplePWM_exit);
MODULE_AUTHOR("AppleCai");  
MODULE_LICENSE("GPL");  



